package com.gjy.statemachine.service.impl;

import com.gjy.statemachine.event.OrderStatusChangeEvent;
import com.gjy.statemachine.module.TbOrder;
import com.gjy.statemachine.repository.TbOrderRepository;
import com.gjy.statemachine.state.OrderStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-07-02 14:42:42
 */
@Service("orderService2")
public class OrderService2Impl {
    private static final Logger log = LoggerFactory.getLogger(OrderService2Impl.class);
    @Resource
    private StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine;
    @Resource
    private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, String> stateMachineMemPersister;
    /*@Resource
    private RedisStateMachinePersister<OrderStatus, OrderStatusChangeEvent> stateMachineRedisPersister;*/
    @Resource
    private TbOrderRepository tbOrderRepository;

    public TbOrder getById(Long id) {
        return tbOrderRepository.findById(id).get();
    }

    /**
     * 创建订单
     */
    public TbOrder create(TbOrder order) {
        order.setStatus(OrderStatus.WAIT_PAYMENT.getKey());
        tbOrderRepository.save(order);
        return order;
    }

    /**
     * 对订单进行支付
     */
    public TbOrder pay(Long id) {
        TbOrder order = tbOrderRepository.findById(id).get();
        log.info("线程名称：{},尝试支付，订单号：{}", Thread.currentThread().getName(), id);
        if (!sendEvent(OrderStatusChangeEvent.PAYED, order)) {
            log.error("线程名称：{},支付失败, 状态异常，订单信息：{}", Thread.currentThread().getName(), order);
            log.error("支付失败, 订单状态异常");
        }
        return order;
    }

    /**
     * 对订单进行发货
     */
    public TbOrder deliver(Long id) {
        TbOrder order = tbOrderRepository.findById(id).get();
        log.info("线程名称：{},尝试发货，订单号：{}", Thread.currentThread().getName(), id);
        if (!sendEvent(OrderStatusChangeEvent.DELIVERY, order)) {
            log.error("线程名称：{},发货失败, 状态异常，订单信息：{}", Thread.currentThread().getName(), order);
            log.error("发货失败, 订单状态异常");
        }
        return order;
    }

    /**
     * 对订单进行确认收货
     */
    public TbOrder receive(Long id) {
        TbOrder order = tbOrderRepository.findById(id).get();
        log.info("线程名称：{},尝试收货，订单号：{}", Thread.currentThread().getName(), id);
        if (!sendEvent(OrderStatusChangeEvent.RECEIVED, order)) {
            log.error("线程名称：{},收货失败, 状态异常，订单信息：{}", Thread.currentThread().getName(), order);
            log.error("收货失败, 订单状态异常");
        }
        return order;
    }

    /**
     * 发送订单状态转换事件
     * synchronized修饰保证这个方法是线程安全的
     */
    private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, TbOrder order) {
        boolean result = false;
        Message<OrderStatusChangeEvent> message = MessageBuilder.withPayload(changeEvent).setHeader("order", order).build();
        try {
            //启动状态机
            orderStateMachine.start();
            //尝试恢复状态机状态
            stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId()));
//            stateMachineRedisPersister.restore(orderStateMachine, String.valueOf(order.getId()));
            result = orderStateMachine.sendEvent(message);
            //持久化状态机状态
            stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId()));
//            stateMachineRedisPersister.persist(orderStateMachine, String.valueOf(order.getId()));
        } catch (Exception e) {
            log.error("订单操作失败:{}", e.getMessage());
        } finally {
            // orderStateMachine.stop();
            if (Objects.nonNull(message)) {
                TbOrder o = (TbOrder) message.getHeaders().get("order");
                if (Objects.nonNull(o) && Objects.equals(o.getStatus(), OrderStatus.FINISH.getKey())) {
                    orderStateMachine.stop();
                }
            }
        }
        return result;
    }

}
